// app_led.c
#include "../inc/app_led.h"
#include "definitions.h"
#include "../inc/serial_service.h"

#define INVERT_PWM_OUTPUT 1

emCtrlState currentMode = BREATH_MODE;

// 全局变量用于保存当前占空比 (0 ~ 100)
static uint8_t  pwmPercent      = 0;
static uint32_t blinkToggleTime = 0;

void LED_PWM_Init(void)
{
    TC3_CompareStart();

    // 设置固定周期为最大值
    TC3_Compare16bitMatch0Set(0xFFFFU);
}

// 将百分比映射到 0 ~ 0xFFFFU
static uint16_t PercentToDutyCycle(uint8_t percent)
{
    percent %= 101;

#if INVERT_PWM_OUTPUT
    return 0xFFFFU - (uint16_t)((uint32_t)percent * 0xFFFFU / 100);
#else
    return (uint16_t)((uint32_t)percent * 0xFFFFU / 100);
#endif
}

int LED_parse(int argc, char **argv)
{
    if (argc == 0)
    {
        Serial_Printf("Usage: led -m num [percent]\n");
        Serial_Printf("  -m 0: Breath mode\n");
        Serial_Printf("  -m 1: Reversal mode\n");
        Serial_Printf("  -m 2 [percent]: Custom duty mode\n");
        Serial_Printf("  -m 3: Blink mode\n");
        Serial_Printf("  -m 4: Fade in mode\n");
        Serial_Printf("  -m 5: Fade out mode\n");
        return -1;
    }

    if (strcmp(argv[0], "-h") == 0)
    {
        Serial_Printf("led -m num [percent]: set LED mode\n");
        return 0;
    }

    if (strcmp(argv[0], "-m") == 0 && argc >= 2)
    {
        char *endptr;
        long  num = strtol(argv[1], &endptr, 10);
        if (endptr == argv[1])
        {
            Serial_Printf("Invalid mode number\n");
            return -1;
        }

        if (num == 2 && argc == 3)
        {
            long percent = strtol(argv[2], &endptr, 10);
            if (endptr == argv[2] || percent < 0 || percent > 100)
            {
                Serial_Printf("Invalid percent value (0~100)\n");
                return -1;
            }
            pwmPercent = (uint8_t)percent;
        }

        if (num >= 0 && num < MODE_NUM)
        {
            currentMode = (emCtrlState)num;
            Serial_Printf("LED mode set to %ld\n", num);
            return 0;
        }
        else
        {
            Serial_Printf("Invalid mode number\n");
            return -1;
        }
    }

    if (strcmp(argv[0], "-p") == 0)
    {
        long percent = strtol(argv[1], NULL, 0);
        if (percent >= 0 && percent <= 100)
        {
            uint16_t duty = (uint16_t)(((uint32_t)percent * 0xFFFFU) / 100);
            Serial_Printf("PWM Duty: %ld%% -> 0x%X\n", percent, duty);
        }
        else
        {
            Serial_Printf("Usage: print -p percent (0~100)\n");
        }
    }

    Serial_Printf("Invalid arguments\n");
    return -1;
}

void LED_StateMachine(void)
{
    switch (currentMode)
    {
    case BREATH_MODE:
    {
        static uint32_t lastTime = 0;
        uint32_t        now      = SYSTICK_GetTickCounter();
        if (now - lastTime > 10)
        {
            static int     direction = 1;
            static uint8_t percent   = 0;

            percent += direction * 1;
            if (percent >= 100)
            {
                direction = -1;
                percent   = 100;
            }
            else if (percent <= 0)
            {
                direction = 1;
                percent   = 0;
            }

            lastTime = now;
            TC3_Compare16bitMatch0Set(PercentToDutyCycle(percent));
        }
        break;
    }

    case REVERSAL_MODE:
    {
        static uint32_t lastToggle = 0;
        uint32_t        now        = SYSTICK_GetTickCounter();
        if (now - lastToggle > 500)
        {
            lastToggle = now;
            pwmPercent = (pwmPercent == 0) ? 100 : 0;
            TC3_Compare16bitMatch0Set(PercentToDutyCycle(pwmPercent));
        }
        break;
    }

    case CUSTOM_MODE:
        TC3_Compare16bitMatch0Set(PercentToDutyCycle(pwmPercent));
        break;

    case BLINK_MODE:
    {
        uint32_t now = SYSTICK_GetTickCounter();
        if (now - blinkToggleTime > 250)
        {
            blinkToggleTime = now;
            pwmPercent      = (pwmPercent == 0) ? 100 : 0;
            TC3_Compare16bitMatch0Set(PercentToDutyCycle(pwmPercent));
        }
        break;
    }

    case FADE_IN_MODE:
    {
        static uint32_t lastTime = 0;
        uint32_t        now      = SYSTICK_GetTickCounter();
        if (now - lastTime > 10)
        {
            lastTime = now;
            if (pwmPercent < 100)
            {
                pwmPercent++;
                TC3_Compare16bitMatch0Set(PercentToDutyCycle(pwmPercent));
            }
        }
        break;
    }

    case FADE_OUT_MODE:
    {
        static uint32_t lastTime = 0;
        uint32_t        now      = SYSTICK_GetTickCounter();
        if (now - lastTime > 10)
        {
            lastTime = now;
            if (pwmPercent > 0)
            {
                pwmPercent--;
                TC3_Compare16bitMatch0Set(PercentToDutyCycle(pwmPercent));
            }
        }
        break;
    }

    default:
        currentMode = BREATH_MODE;
        break;
    }
}
